// 包含 NS16550a UART 驱动.

#include "types.h"
#include "defs.h"
#include "memlayout.h"

// UART 控制寄存器的内存映射地址
#define RHR 0                 // 接收保持寄存器 (只读)
#define THR 0                 // 发送保持寄存器 (只写)
#define IER 1                 // 中断使能寄存器
#define FCR 2                 // FIFO 控制寄存器
#define ISR 2                 // 中断状态寄存器
#define LCR 3                 // 线路控制寄存器
#define LSR 5                 // 线路状态寄存器

#define Reg(reg) ((volatile unsigned char *)(UART0 + reg))

#define LSR_TX_IDLE (1 << 5) // 发送器空闲

// 初始化 UART
void
uartinit(void)
{
  // 禁用中断
  *Reg(IER) = 0x00;

  // 设置波特率为 38.4k
  *Reg(LCR) = 0x80; // 开启 DLAB 以设置波特率
  *Reg(0) = 0x03;   // 波特率除数低字节
  *Reg(1) = 0x00;   // 波特率除数高字节
  
  // 设置线路控制：8位数据位, 1位停止位, 无校验
  *Reg(LCR) = 0x03; // 关闭 DLAB

  // 使能并清空 FIFO
  *Reg(FCR) = 0x07;

  // 重新使能接收中断
  *Reg(IER) = 0x01;
}

// 向 UART 发送一个字符
void
uart_putc(char c)
{
  // 等待发送器空闲
  while((*Reg(LSR) & LSR_TX_IDLE) == 0)
    ;
  // 写入要发送的字符
  *Reg(THR) = c;
}

// 从 UART 读取一个字符
// 如果没有字符可读，返回 -1
int
uart_getc(void)
{
  if(*Reg(LSR) & 0x01){
    // 有数据可读
    return *Reg(RHR);
  } else {
    return -1;
  }
}